package com.ship.service.impl;

import com.ship.entity.bo.DeviceInfo;
import com.ship.entity.bo.UserRole;
import com.ship.entity.bo.Users;
import com.ship.entity.dto.JsonRequest;
import com.ship.entity.dto.UserInfoResponse;
import com.ship.jwt.JwtAuthenticationRequest;
import com.ship.jwt.JwtTokenUtil;
import com.ship.jwt.JwtUser;
import com.ship.mapper.UserMapper;
import com.ship.mapper.UserRoleMapper;
import com.ship.service.AuthService;
import com.ship.service.DeviceInfoService;
import com.ship.util.DateUtils;
import com.ship.util.NetworkUtils;
import com.ship.util.TimestampPkGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
import java.util.UUID;


@Service
public class AuthServiceImpl implements AuthService {

    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Resource
    private UserMapper userMapper;
    @Resource
    private UserRoleMapper userRoleMapper;

    @Value("${jwt.tokenHead}")
    private String tokenHead;
    @Value("${vip_day}")
    private int vipDay;
    @Autowired
    private DeviceInfoService deviceInfoService;

   /* @Autowired
    public AuthServiceImpl(
            AuthenticationManager authenticationManager,
            UserDetailsService userDetailsService,
            JwtTokenUtil jwtTokenUtil,
            UserRepository userRepository) {
        this.authenticationManager = authenticationManager;
        this.userDetailsService = userDetailsService;
        this.jwtTokenUtil = jwtTokenUtil;
        this.userRepository = userRepository;
    }*/

    @Override
    public Users register(Users userToAdd) {
        final String username = userToAdd.getUsername();
        if(userMapper.findByUsername(username)!=null) {
            return null;
        }
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        final String rawPassword = userToAdd.getPassword();
        userToAdd.setPassword(encoder.encode(rawPassword));
        userToAdd.setLastPasswordResetDate(new Date());
        userToAdd.setCreateTime(new Date());
        userToAdd.setAccountNonExpired(true);
        userToAdd.setAccountNonLocked(true);
        userToAdd.setEnabled(true);
        userToAdd.setVipTime(DateUtils.addDay(new Date(),vipDay));
        userToAdd.setCredentialsNonExpired(true);
        String userid = UUID.randomUUID().toString().replace("-","");
        userToAdd.setId(userid);
        userToAdd.setSeqNo(new TimestampPkGenerator().next(getClass()));
        userMapper.insert(userToAdd);

        UserRole userRole = new UserRole();
        String roleId = UUID.randomUUID().toString().replace("-","");
        userRole.setId(roleId);
        userRole.setUserId(userid);
        userRole.setRoleId("1");
        userRoleMapper.insert(userRole);
        return userToAdd;
    }

    @Override
    public UserInfoResponse login(JsonRequest<JwtAuthenticationRequest> authenticationRequest, HttpServletRequest request) {
        UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken(authenticationRequest.getParameters().getUsername(), authenticationRequest.getParameters().getPassword());
        // Perform the security
        final Authentication authentication = authenticationManager.authenticate(upToken);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        Users users = userMapper.findByUsername(authenticationRequest.getParameters().getUsername());
        // Reload password post-security so we can generate token
        final UserDetails userDetails = userDetailsService.loadUserByUsername(authenticationRequest.getParameters().getUsername());
        final String token = jwtTokenUtil.generateToken(userDetails);
        UserInfoResponse userInfoResponse =new UserInfoResponse();
        userInfoResponse.setToken(token);
        userInfoResponse.setUserId(users.getId());
        userInfoResponse.setUsername(authenticationRequest.getParameters().getUsername());
        //添加设备信息表
        DeviceInfo deviceInfo = new DeviceInfo();
        deviceInfo.setCreateTime(new Date());
        deviceInfo.setDeviceId(authenticationRequest.getDeviceId());
        deviceInfo.setLocation(authenticationRequest.getAddress());
        deviceInfo.setUserId(users.getId());
        deviceInfo.setDeviceIp(NetworkUtils.getIpAddr(request));
        deviceInfo.setDevicePlatform(authenticationRequest.getClient());
        deviceInfo.setTel(authenticationRequest.getTel());
        String id = UUID.randomUUID().toString().replace("-","");
        deviceInfo.setId(id);
        try {
            deviceInfoService.insert(deviceInfo);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return userInfoResponse;
    }

    @Override
    public String refresh(String oldToken) {
        final String token = oldToken.substring(tokenHead.length());
        String username = jwtTokenUtil.getUsernameFromToken(token);
        JwtUser user = (JwtUser) userDetailsService.loadUserByUsername(username);
        if (jwtTokenUtil.canTokenBeRefreshed(token, user.getLastPasswordResetDate())){
            return jwtTokenUtil.refreshToken(token);
        }
        return null;
    }

    @Override
    public UserInfoResponse login(String username, String password) {
        UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken(username, password);
        // Perform the security
        final Authentication authentication = authenticationManager.authenticate(upToken);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        Users users = userMapper.findByUsername(username);
        // Reload password post-security so we can generate token
        final UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        final String token = jwtTokenUtil.generateToken(userDetails);
        UserInfoResponse userInfoResponse =new UserInfoResponse();
        userInfoResponse.setToken(token);
        userInfoResponse.setUserId(users.getId());
        userInfoResponse.setUsername(username);
        return userInfoResponse;
    }

    @Override
    public Users findByUsername(String username) {
        Users users = userMapper.findByUsername(username);
        if(users == null){
            return null;
        }
        List<String> a = userMapper.findRoleByUserId(users.getId());
        users.setAuthorities(a);
        return users;
    }
}
